package main

import (
	"fmt"
	"github.com/gdamore/tcell"
	"github.com/gdamore/tcell/encoding"
	"math"
	"os"
	"strings"
	"unicode"
)

var (
	white         = tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorRed)
	StyleLogInfo  = tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorGreen)
	StyleLogDebug = tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorOrange)
	StyleLogError = tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorRed)
)

type Screen struct {
	ScreenObj   tcell.Screen
	LogStr      string
	LogType     string
	EventEsc    func()
	EventMap    map[string]func()
	CountBtnEsc int
}

func NewScreen() *Screen {
	s, err := tcell.NewScreen()
	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	if err := s.Init(); err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	return &Screen{ScreenObj: s, EventMap: make(map[string]func())}
}

func (s *Screen) EmitStr(x, y int, style tcell.Style, str string) {
	for _, c := range str {
		s.ScreenObj.SetCell(x, y, style, c)
		if unicode.Is(unicode.Han, c) { // 如果是汉字，就增加两个宽度
			x += 2
		} else if c >= 65281 && c <= 65374 {
			x += 2
		} else { // 如果是英文，就增加一个宽度
			x += 1
		}
	}
}

func (s *Screen) GetStrWidth(str string) (width int) {
	for _, c := range str {
		if unicode.Is(unicode.Han, c) { // 如果是汉字，就增加两个宽度
			width += 2
		} else if c >= 65281 && c <= 65374 {
			width += 2
		} else { // 如果是英文，就增加一个宽度
			width += 1
		}
	}
	return
}

func (s *Screen) EventRegister(Event string, Func func()) {
	s.EventMap[Event] = Func
}

func (s *Screen) LogPrint() {
	s.ScreenObj.Clear()
	x, y := s.ScreenObj.Size()
	LogStr := s.LogStr
	style := white
	switch s.LogType {
	case "INFO":
		LogStr = "  INFO:" + LogStr
		style = StyleLogInfo
	case "ERROR":
		LogStr = "  ERROR:" + LogStr
		style = StyleLogError
	case "DEBUG":
		LogStr = "  DEBUG:" + LogStr
		style = StyleLogDebug
	default:
		LogStr = "  LOG:" + LogStr
	}
	LogStr = LogStr + strings.Repeat(" ", int(math.Max(0, float64(x-s.GetStrWidth(LogStr)))))
	s.EmitStr(0, y-1, style, LogStr)
}

func (s *Screen) LogInfo(LogStr string) {
	s.LogType = "INFO"
	s.LogStr = LogStr
}

func (s *Screen) LogDebug(LogStr string) {
	s.LogType = "DEBUG"
	s.LogStr = LogStr
}

func (s *Screen) LogError(LogStr string) {
	s.LogType = "ERROR"
	s.LogStr = LogStr
}

func (s *Screen) Run() {
	for {
		s.LogPrint()
		//s.ScreenObj.Clear()
		//s.EmitStr(2, 3, white, fmt.Sprintf(posFmt, mx, my))
		//s.EmitStr(2, 4, white, fmt.Sprintf(btnFmt, bStr))
		//s.EmitStr(2, 5, white, fmt.Sprintf(keyFmt, lks))
		s.ScreenObj.Show()
		ev := s.ScreenObj.PollEvent()
		switch ev := ev.(type) {
		case *tcell.EventResize:
			s.ScreenObj.Sync()
			w, h := s.ScreenObj.Size()
			s.LogDebug(fmt.Sprintf("EventResize: %v - %v", w, h))
		case *tcell.EventKey:
			s.LogInfo(fmt.Sprintf("按键按下：[%v][%v]", ev.Name(), ev.Key()))
			if Func, ok := s.EventMap[ev.Name()]; ok {
				Func()
			}
			if ev.Key() == tcell.KeyEscape {
				if s.EventEsc == nil {
					s.LogStr = "EventEsc == nil"
				} else {
					s.EventEsc()
				}
				s.CountBtnEsc++
				if s.CountBtnEsc > 1 {
					s.ScreenObj.Fini() // 退出前必须执行，否则无法正常恢复终端
					os.Exit(0)
				}
			} else {
				s.CountBtnEsc = 0
				if ev.Rune() == 'C' || ev.Rune() == 'c' {
					s.ScreenObj.Clear()
				}
			}
		}
	}
}

func main() {
	encoding.Register()
	s := NewScreen()
	s.EventEsc = func() {
		s.LogStr = "Esc 按下，再按一下退出！"
	}
	s.EventRegister("Rune[h]", func() {
		s.LogInfo("[h] Help: Press ESC twice to exit, C to clear.")
	})
	//s.EventRegister("Right", func() {
	//	s.LogInfoStr = "上下左右：右"
	//})
	//s.EventRegister("Left", func() {
	//	s.LogInfoStr = "上下左右：左"
	//})
	//s.EventRegister("Up", func() {
	//	s.LogInfoStr = "上下左右：上"
	//})
	//s.EventRegister("Down", func() {
	//	s.LogInfoStr = "上下左右：下"
	//})
	s.Run()
}
